﻿#include "LargeSampleSimulationUI.h"

using namespace std;
#include <qobject.h>
#include <windows.h>
#include "synchapi.h"
#include <quuid.h>
#include <fstream>
#include <QMessageBox>



LargeSampleSimulationUI::LargeSampleSimulationUI(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);

	setWindowTitle(QString::fromLocal8Bit("YL声光尾流复合制导并行推演仿真平台"));
	//初始最大化
	setWindowState(Qt::WindowMaximized);
	//菜单栏
	//QMenuBar *mBar = menuBar();
	//setMenuBar(mBar);

	//用一线程循环处理接收到的数据
	calcuthread = new CalcuThread();
	calcuthread->start();

	recvLength = 0;
	connect(calcuthread, SIGNAL(saveRes(ResStruct*, int)), this, SLOT(OnActionSaveRes(ResStruct*, int)));
	//connect(tablewidget, &FactorTableWidget::loadFileInfo, this, &LargeSampleSimulationUI::OnLoadFileInfo);
	//connect(calcuthread, SIGNAL(printInfo(QString)), ui.textBrowser_info, SLOT(append(QString)));
	
	//tablewidget = nullptr;
	sql = new Usersql();
	sql->DatabaseConnect();
	query = (QSqlQuery)sql->getDB();
	model = new QSqlTableModel(this);
	status = WAITFORCONNECT;
	curRecvId = -1;
	curXDNums = 0;
	curRepeatNum = 0;

	//curTaskId = 0;
	////curXDNums = 0;
	//curDisplayId = 0;
	//curSendWindowLen = 0;
	//plot = new PlotPictureWidget;
	resNameList << QString::fromLocal8Bit("结果1") << QString::fromLocal8Bit("结果2") << QString::fromLocal8Bit("结果3") << QString::fromLocal8Bit("结果4") <<
		QString::fromLocal8Bit("结果5") << QString::fromLocal8Bit("结果6") << QString::fromLocal8Bit("结果7") << QString::fromLocal8Bit("结果8");	//结果名
	//isGKDataLoad = false;
	ui.selectResBox->addItems(resNameList);
	//pca = new PCAclass;
	Init();
	Monitorinit();
}
LargeSampleSimulationUI :: ~LargeSampleSimulationUI()
{

}

void LargeSampleSimulationUI::setUsersqlptr(Usersql* val)
{
	sql = val;
}

void LargeSampleSimulationUI::settaskStatusFinish()
{
	taskStatus = QString::fromLocal8Bit("计算完成");
	emit(changeTaskStatus(curTaskId, taskStatus));
}

void LargeSampleSimulationUI::Init() {

	//根据显示内容，选择数据库的表，此处选择任务表，即"taskList"。数据库表名见bool Usersql::DatabaseConnect()
	model->setTable("taskList");
	//model->setTable("dataSave");
	model->select();
	model->setEditStrategy(QSqlTableModel::OnManualSubmit);

	model->setHeaderData(0, Qt::Horizontal, QString::fromLocal8Bit(" 序号 "));
	model->setHeaderData(1, Qt::Horizontal, QString::fromLocal8Bit("   任务   "));
	model->setHeaderData(2, Qt::Horizontal, QString::fromLocal8Bit("   文件保存路径   "));
	model->setHeaderData(3, Qt::Horizontal, QString::fromLocal8Bit("提交时间"));
	model->setHeaderData(4, Qt::Horizontal, QString::fromLocal8Bit("   状态   "));
	model->insertColumn(5);//在模型的第4列后面插入一列，放按钮
	model->setHeaderData(5, Qt::Horizontal, QString::fromLocal8Bit("   任务详情   "));

	//将数据模型与TableView绑定
	ui.tableView->setModel(model);
	//最后一列插入打开按钮
	for (int i = 0; i < getModelRowCount(); i++)
	{
		QPushButton *btn = new QPushButton(QString::fromLocal8Bit("查看"));
		btn->setProperty("row", i);
		connect(btn, SIGNAL(clicked()), this, SLOT(OnPushbuttonCheck()));
		ui.tableView->setIndexWidget(model->index(i, 5), btn);
	}
	//ResizeToContents
	//设置列宽 行高   固定行高自适应列宽
	ui.tableView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
	ui.tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
	ui.tableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
	ui.tableView->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
	ui.tableView->horizontalHeader()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
	ui.tableView->horizontalHeader()->setSectionResizeMode(4, QHeaderView::ResizeToContents);

	ui.tableView->setAlternatingRowColors(true);//隔行变色  
	ui.tableView->setSelectionBehavior(QAbstractItemView::SelectRows);//设置选中时为整行选中   
	ui.tableView->setContextMenuPolicy(Qt::CustomContextMenu);//设置可弹出右键菜单

	popMenu = new QMenu(ui.tableView);
	actionUpdateInfo = new QAction();
	actionDelInfo = new QAction();
	actionUpdateInfo->setText(QString::fromLocal8Bit("刷新"));
	actionDelInfo->setText(QString::fromLocal8Bit("删除"));
	popMenu->addAction(actionUpdateInfo);
	popMenu->addAction(actionDelInfo);
	//connect(actionUpdateInfo, SIGNAL(triggered()), this, SLOT(appendAction_triggered()));
	connect(actionDelInfo, SIGNAL(triggered()), this, SLOT(OnDeletTask()));
	connect(ui.tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(OnPopMenue(QPoint)));

	ui.tableWidget->setRowCount(10);
	ui.tableWidget->setColumnCount(10);
	ui.tableWidget->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);//固定行高
	ui.tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//列宽填充
	//ui.tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);//自适应列宽
	ui.tableWidget->setAlternatingRowColors(true);//隔行变色
	//ui.pushButton_5->setEnabled(false);             //测试

	//历史，输出，资源监控三个窗口并排放在界面底部
	addDockWidget(Qt::BottomDockWidgetArea, ui.dock_history_2);
	splitDockWidget(ui.dock_history_2, ui.dock_printInfo, Qt::Horizontal);
	splitDockWidget(ui.dock_printInfo, ui.dock_resourcemonitor_2, Qt::Horizontal);

	//初始化效能评估功能无法使用
	//ui.comboBox_2->setEnabled(FALSE); //测试时可用
	//初始化stackedwidget在导入页面
	ui.stackedWidget->setCurrentIndex(0);
	connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(OnActionCreateGongKuang()));
	connect(ui.pushButton_2, SIGNAL(clicked()), this, SLOT(OnActionCreateXiangding()));
	connect(ui.action_historysearch, SIGNAL(triggered()), this, SLOT(OnActionStartSearch()));

	connect(this, SIGNAL(updateTaskInfo(const int, const QString&, const QString&, const QString&)),
		this, SLOT(OnUpdateTaskInfo(const int, const QString&, const QString&, const QString&)));
	//connect(tablewidget, SIGNAL(updateTaskInfo(const int, const QString&, const QString&)),
	//	this, SLOT(OnUpdateTaskInfo(const int, const QString&, const QString&)));
	connect(this, SIGNAL(changeTaskStatus(const int, const QString&)),
		this, SLOT(OnChangeTaskStatus(const int, const QString&)));
	connect(this, SIGNAL(StartRun(const QString, int, int)), this, SLOT(OnStartRun(const QString, int, int)));

}

void LargeSampleSimulationUI::Monitorinit()
{
	connect(calcuthread, SIGNAL(getresource(Resource)), this, SLOT(Updateresource(Resource)));
	QFont font;
	font.setFamily("宋体");
	ui.CPUMonitor->addGraph();//添加数据曲线
	//CPU使用率初始化
	//添加标题
	QString CPUMonitorTitle = QString::fromLocal8Bit("当前CPU使用率：0%");
	ui.CPUMonitor->plotLayout()->insertRow(0);
	CPU_title = new QCPTextElement(ui.CPUMonitor, CPUMonitorTitle);
	ui.CPUMonitor->plotLayout()->addElement(0, 0, CPU_title);
	ui.CPUMonitor->graph(0)->addData(0, 0);//初始化0时刻为0%
	// 为坐标轴添加标签
	ui.CPUMonitor->xAxis->setLabelFont(font);
	ui.CPUMonitor->xAxis->setLabel(QString::fromLocal8Bit("时间/s"));
	ui.CPUMonitor->yAxis->setLabel(QString::fromLocal8Bit("CPU使用率/%"));
	// 设置坐标轴的范围
	ui.CPUMonitor->xAxis->setRange(0, 10);
	ui.CPUMonitor->yAxis->setRange(0, 100);
	// 仅显示0和50和100刻度线，而不显示中间的刻度线
	ui.CPUMonitor->yAxis->ticker()->setTickCount(2); // 仅显示0和100的刻度线
	ui.CPUMonitor->legend->setVisible(false); // 不显示图例
	// 设置折线颜色
	ui.CPUMonitor->graph(0)->setPen(QPen(QColor(173, 216, 230)));  // 使用淡蓝色，RGB(173, 216, 230)
	// 添加填充区域
	ui.CPUMonitor->graph(0)->setBrush(QBrush(QColor(173, 216, 230, 100))); // 使用带透明度的淡蓝色，透明度为 100
	// 填充区域从折线到 x 轴
	ui.CPUMonitor->graph(0)->setChannelFillGraph(ui.CPUMonitor->graph(0)); // 这将使用与折线相同的数据点来填充区域


	//内存占用率初始化
	ui.MemMonitor->addGraph();//添加数据曲线
	QString MemMonitorTitle = QString::fromLocal8Bit("当前内存占用率：0%");
	ui.MemMonitor->plotLayout()->insertRow(0);
	Mem_title = new QCPTextElement(ui.MemMonitor, MemMonitorTitle);
	ui.MemMonitor->plotLayout()->addElement(0, 0, Mem_title);
	ui.MemMonitor->graph(0)->addData(0, 0);//初始化0时刻为0%
	// 为坐标轴添加标签
	ui.MemMonitor->xAxis->setLabelFont(font);
	ui.MemMonitor->xAxis->setLabel(QString::fromLocal8Bit("时间/s"));
	ui.MemMonitor->yAxis->setLabel(QString::fromLocal8Bit("内存占用用率/%"));
	// 设置坐标轴的范围
	ui.MemMonitor->xAxis->setRange(0, 10);
	ui.MemMonitor->yAxis->setRange(0, 100);
	// 仅显示0和50和100刻度线，而不显示中间的刻度线
	ui.MemMonitor->yAxis->ticker()->setTickCount(2); // 仅显示0和100的刻度线
	ui.MemMonitor->legend->setVisible(false); // 不显示图例
	// 设置折线颜色
	ui.MemMonitor->graph(0)->setPen(QPen(QColor(173, 216, 230)));  // 使用淡蓝色，RGB(173, 216, 230)
	// 添加填充区域
	ui.MemMonitor->graph(0)->setBrush(QBrush(QColor(173, 216, 230, 100))); // 使用带透明度的淡蓝色，透明度为 100
	// 填充区域从折线到 x 轴
	ui.MemMonitor->graph(0)->setChannelFillGraph(ui.MemMonitor->graph(0)); // 这将使用与折线相同的数据点来填充区域

	//timer = new QTimer(this);
	//timer->setInterval(1000);
	//connect(timer, SIGNAL(timeout()), this, SLOT(Updateresource()));
	//timer->start();


}

//LargeSampleSimulationUI::resource  LargeSampleSimulationUI::getresource() {
//	// 获取 CPU 使用率和内存使用率的数据,这里只是测试，需要socket通信获取
//	double cpuUsage = 75.234; // 示例值
//	double memUsage = 60.569; // 示例值
//	resource result;
//	result.CPUUsage = cpuUsage;
//	result.MemUsage = memUsage;
//	return result;
//}

void LargeSampleSimulationUI::Updateresource(Resource resource)
{
	time++;//调用时时刻+1
	double CPU = resource.cpu_usage_rate;
	double Mem = resource.mem_usage_rate;
	if (time < 10) {
		ui.CPUMonitor->xAxis->setRange(0, 10);
		ui.MemMonitor->xAxis->setRange(0, 10);
	}
	else {
		ui.CPUMonitor->xAxis->setRange(time - 10, time);
		ui.MemMonitor->xAxis->setRange(time - 10, time);
	}
	ui.CPUMonitor->graph(0)->addData(time, CPU);
	ui.MemMonitor->graph(0)->addData(time, Mem);
	ui.CPUMonitor->yAxis->setRange(0, 100);
	ui.MemMonitor->yAxis->setRange(0, 100);
	QString stringCPU = QString::number(CPU);
	QString stringMem = QString::number(Mem);
	QString newCPUtitle = QString::fromLocal8Bit("当前CPU使用率：") + stringCPU + "%";
	QString newMemtitle = QString::fromLocal8Bit("当前内存占用率：") + stringMem + "%";
	CPU_title->setText(newCPUtitle);
	Mem_title->setText(newMemtitle);
	// 仅显示0和50和100刻度线，而不显示中间的刻度线
	ui.CPUMonitor->yAxis->ticker()->setTickCount(2); // 仅显示0和100的刻度线
	ui.CPUMonitor->legend->setVisible(false); // 不显示图例
	ui.MemMonitor->yAxis->ticker()->setTickCount(2); // 仅显示0和100的刻度线
	ui.MemMonitor->legend->setVisible(false); // 不显示图例
	// 设置折线颜色
	ui.CPUMonitor->graph(0)->setPen(QPen(QColor(173, 216, 230)));  // 使用淡蓝色，RGB(173, 216, 230)
	ui.MemMonitor->graph(0)->setPen(QPen(QColor(173, 216, 230)));  // 使用淡蓝色，RGB(173, 216, 230)
	// 添加填充区域
	ui.CPUMonitor->graph(0)->setBrush(QBrush(QColor(173, 216, 230, 100))); // 使用带透明度的淡蓝色，透明度为 100
	ui.MemMonitor->graph(0)->setBrush(QBrush(QColor(173, 216, 230, 100))); // 使用带透明度的淡蓝色，透明度为 100
	// 填充区域从折线到 x 轴
	ui.CPUMonitor->graph(0)->setChannelFillGraph(ui.CPUMonitor->graph(0)); // 与折线相同的数据点来填充区域
	ui.MemMonitor->graph(0)->setChannelFillGraph(ui.MemMonitor->graph(0)); // 与折线相同的数据点来填充区域
	ui.CPUMonitor->replot();
	ui.MemMonitor->replot();

}

//点击按钮选择导入或输入因素水平表
void LargeSampleSimulationUI::on_AddButton_clicked()
{
	curTaskId = 0;
	curXDNums = 0;
	curDisplayId = 0;
	curSendWindowLen = 0;
	plot = new PlotPictureWidget;
	//resNameList << QString::fromLocal8Bit("结果1") << QString::fromLocal8Bit("结果2") << QString::fromLocal8Bit("结果3") << QString::fromLocal8Bit("结果4") <<
	//	QString::fromLocal8Bit("结果5") << QString::fromLocal8Bit("结果6") << QString::fromLocal8Bit("结果7") << QString::fromLocal8Bit("结果8");	//结果名
	isGKDataLoad = false;
	//ui.selectResBox->addItems(resNameList);
	pca = new PCAclass;

	setUsersqlptr(sql);

	NewChooseWindow = new choose;
	connect(NewChooseWindow, SIGNAL(ImportButtonClicked()), this, SLOT(TableImport()));
	connect(NewChooseWindow, SIGNAL(ShowFactorSignal(QStringList, std::vector<std::vector<float>>)), this, SLOT(ShowInput(QStringList, std::vector<std::vector<float>>)));
	NewChooseWindow->show();
}

void LargeSampleSimulationUI::OnActionStartSearch()
{
	NewSearchwindow = new SearchHistory;
	connect(NewSearchwindow, SIGNAL(SearchHistoryClosed()),this,SLOT(ReloadSql()));
	NewSearchwindow->show();
}

void LargeSampleSimulationUI::on_ReturnInitialButton_clicked()//返回初始界面重新导入或输入因素水平表
{
	if (plot)
		delete plot;
	if (modelAnova)
		delete modelAnova;
	if (pca)
		delete pca;
	ui.stackedWidget->setCurrentIndex(0);
	ui.comboBox_2->setCurrentIndex(-1);
	ui.comboBox_2->setEnabled(false);

	//重置所有显示控件内容
	ui.lineEdit->clear();
	ui.lineEdit_2->clear();
	ui.lineEdit_3->clear();
	ui.tableWidget->clear();
	ui.tableWidget_2->clear();
	ui.tableWidget_3->clear();
	ui.tableWidget_4->clear();
	ui.tableWidget_6->clear();
	ui.tableWidget_7->clear();
	ui.tableWidget_8->clear();
	ui.tableWidget_10->clear();

	//重置因素名称和因子水平
	factorNames.clear();
	FactorLevelData.clear();

	//重置分析状态
	analyStatus[0] = false;
	analyStatus[1] = false;
	analyStatus[2] = false;
}

void LargeSampleSimulationUI::OnActionReturn()
{
	ui.stackedWidget->setCurrentIndex(1);
	ui.tabWidget->setCurrentIndex(2);
}

void LargeSampleSimulationUI::ShowInput(QStringList factors, std::vector<std::vector<float>> FactorData)
{
	FactorLevelData = FactorData;
	factorNames = factors;

	ui.stackedWidget->setCurrentIndex(1);
	ui.tabWidget->setCurrentIndex(0);
	ui.tableWidget->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);//固定行高
	ui.tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//列宽自动填充
	//ui.lineEdit->setText(filePath);
	int columnCount = factors.count();//获取因子个数
	int rowCount = FactorData.size();//获取水平个数
	//设置行、列数
	ui.tableWidget->setColumnCount(columnCount);
	ui.tableWidget->setRowCount(rowCount);

	//将数据显示在TableWidget中
	ui.tableWidget->setHorizontalHeaderLabels(factors);
	for (int i = 0; i < rowCount; i++)
	{
		for (int j = 0; j < columnCount; j++)
		{
			QTableWidgetItem *item = new QTableWidgetItem(QString::number(FactorLevelData[i][j], 'f', 6));
			ui.tableWidget->setItem(i, j, item);
		}
	}
	taskStatus = QString::fromLocal8Bit("因素水平表已读");
}

//导入因素水平表
void LargeSampleSimulationUI::TableImport()
{

	ui.stackedWidget->setCurrentIndex(1);
	ui.tabWidget->setCurrentIndex(0);
	//桌面打开//Qt4
	//QString desktopDir=QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
	//Qt 5
	QString desktopDir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
	//选择Excel文件，并获取路径
	QString path_FL = QFileDialog::getOpenFileName(NULL, "选择Excel", desktopDir, "*.xlsx *.xls");
	if (path_FL.isNull()) {
		QMessageBox::warning(NULL, QString::fromLocal8Bit("错误提示"), QString::fromLocal8Bit("无法打开excel文件"));
		ui.stackedWidget->setCurrentIndex(0);
		return;
	}
	ui.lineEdit->setText(path_FL);

	//读取excel
	QSqlDatabase db = QSqlDatabase::addDatabase("QODBC", "excel");
	if (!db.isValid())
	{
		QMessageBox::warning(NULL, QString::fromLocal8Bit("错误提示"), QString::fromLocal8Bit("数据库驱动异常"));
		db.close();
		ui.stackedWidget->setCurrentIndex(0);
		return;
	}

	QString dsn = QString("Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};Readonly=TRUE;DBQ=%1;").arg(path_FL);
	db.setDatabaseName(dsn);
	if (!db.open())
	{
		QSqlError error = db.lastError();
		QString str = error.text();
		QMessageBox::warning(NULL, QString::fromLocal8Bit("错误提示"), str);//QString::fromLocal8Bit("无法打开数据库"));
		db.close();
		ui.stackedWidget->setCurrentIndex(0);
		return;
	}
	QSqlQuery query(db);
	QString tableName = "Sheet1$"; //sheet名，$是必须的
	QString sql = "select * from [" + tableName + "]";
	query.exec(sql);

	//重新设置行、列数
	QSqlRecord rec = query.record();
	int cols = rec.count();
	ui.tableWidget->setColumnCount(cols);
	ui.tableWidget->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);//固定行高
	ui.tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//列宽自动填充
	//将因素名保存在factorNames中(excel第一行数据将作为数据库字段，因此遍历字段以获取因素名)
	for (int i = 0; i < cols; i++)
	{
		factorNames.push_back(rec.fieldName(i));
	}
	//设置表头为因素名
	ui.tableWidget->setHorizontalHeaderLabels(factorNames);


	//将从数据库查询到的数据显示在QTableWidget中
	//将数据保存的二维数组FactorLevelData中
	int row = 0; //行号
	FactorLevelData.clear();
	while (query.next())   	//每次query就是一行数据
	{
		if (row > ui.tableWidget->rowCount() - 1)
			ui.tableWidget->insertRow(row);
		std::vector<float> rowData;
		for (int i = 0; i < cols; i++)
		{
			float n = query.value(i).toDouble();
			rowData.push_back(n);
			QTableWidgetItem *item = new QTableWidgetItem(QString::number(query.value(i).toDouble(), 'f', 6));
			ui.tableWidget->setItem(row, i, item);
		}
		FactorLevelData.push_back(rowData);
		row++;
	}
	query.clear();
	db.close();
	taskStatus = QString::fromLocal8Bit("因素水平表已读");	
}

void LargeSampleSimulationUI::OnActionRun()
{
	emit(StartRun(m_TaskDataFolderPath, curXDNums, curSendWindowLen));
	taskStatus = QString::fromLocal8Bit("开始计算");
	emit(changeTaskStatus(curTaskId, taskStatus));
}

void LargeSampleSimulationUI::OnActionPlotShow()
{
	//打开界面时更新当前任务数据文件夹路径
	//点击按钮 判断按钮所在行数 即结果表文件名中的序号
	//获取按钮的指针
	QPushButton *pushButton_ = dynamic_cast<QPushButton*>(this->sender());
	if (NULL == pushButton_)
	{
		return;
	}

	// 获取该按钮所在表格的行号
	QString row = pushButton_->property("row").toString();
	QString fileName = m_TaskDataFolderPath + "\\res_plot_" + row + ".txt";

	plot->show();
	plot->addPicture(fileName);
}

void LargeSampleSimulationUI::onActionEvaluation()
{
	OndisplayTxt_avr_res();
	switch (ui.comboBox_2->currentIndex())
	{
		case 0:
			if (analyStatus[0] == false)
			{
				PcaAnalysis();
				analyStatus[0] = true;
			}
			ui.stackedWidget->setCurrentIndex(2);
		    break; 
		case 1:
			{
			if (analyStatus[1] == false)
			{
				CorrelationAnalysis();
				analyStatus[2] = true;
			}
			ui.stackedWidget->setCurrentIndex(3);
			break; 
			}	
		case 2:
			if (analyStatus[2] == false)
			{
				std::vector<float> va;
				VarianceAnalysis(0, 8, 8, va);
				analyStatus[1] = true;
			}
			ui.stackedWidget->setCurrentIndex(4);
			break;
		default:
			break;
	}
}

void LargeSampleSimulationUI::OnAnovaShow()
{
	int celectResIdx = ui.selectResBox->currentIndex();
	int sampleNum = ui.lineEdit_sampleNum->text().toInt();
	int minSampleSize = ui.lineEdit_minSampleSize->text().toInt();

	std::vector<float> anov_res;
	if (!VarianceAnalysis(celectResIdx, sampleNum, minSampleSize, anov_res))
		QMessageBox::warning(NULL, QString::fromLocal8Bit("方差分析失败"), QString::fromLocal8Bit("样本容量不符合要求，请尝试调整相关设置"));
	//将当前绘制文件名添加到右侧显示列表中
	QList<QStandardItem*> add_items;
	add_items << new QStandardItem(ui.selectResBox->currentText());
	for (auto insert_data : anov_res) {
		add_items << new QStandardItem(QString::number(insert_data));
	}

	modelAnova->appendRow(add_items);
}

void LargeSampleSimulationUI::PcaAnalysis()
{
	//Eigen::MatrixXd matrix(curXDNums, resCol);
	Eigen::MatrixXd matrix(8, 8);     //测试用
	//for (int i = 0; i < curXDNums; i++)
	//	matrix.row(i) = VectorXd::Map(&vAvrRes[i][0], vAvrRes[i].size());
	for (int i = 0; i < matrix.rows(); ++i)
	{
		for (int j = 0; j < matrix.cols(); ++j)
		{
			matrix(i, j) = vAvrRes_pca[i][j];
		}
	}


	double retained_variance = 0.95;//选择足够多的主成分以保证保留的特征值之和占总特征值之和的比例至少为0.95（即损失率不超过5%）
	pca_result = pca->PCA(matrix, retained_variance);

	////结果写文件
	////cout << "主成分:\n" << pca_result.transformed_data << endl;
	//QString transformed_dataFileName = m_TaskDataFolderPath + "\\transformed_data.txt";
	//std::ofstream fout1(transformed_dataFileName.toStdString(), std::ios::out);
	//fout1 << pca_result.transformed_data << std::endl;
	//fout1.flush();
	//fout1.close();
	////cout << "综合得分:\n" << pca_result.score << endl;
	//QString scoreFileName = m_TaskDataFolderPath + "\\score.txt";
	//std::ofstream fout2(scoreFileName.toStdString(), std::ios::out);
	//fout2 << pca_result.score << std::endl;
	//fout2.flush();
	//fout2.close();

	//主成分结果、综合得分显示 ------ tableWidget_8
	ui.tableWidget_8->setAlternatingRowColors(true);//隔行变色
	ui.tableWidget_8->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);//行高自动填充
	ui.tableWidget_8->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//列宽自动填充
	int rowsCount = pca_result.transformed_data.rows();
	int cloumCount = pca_result.transformed_data.cols();
	ui.tableWidget_8->setRowCount(rowsCount + 1);
	ui.tableWidget_8->setColumnCount(cloumCount + 1);
	QStringList headerList_8;

	//表头
	for (int i = 0; i < cloumCount; i++)
	{
		QString headerStr = QString::fromLocal8Bit("主成分") + QString::number(i + 1);
		headerList_8.append(headerStr);
	}
	headerList_8.append(QString::fromLocal8Bit("综合得分"));
	ui.tableWidget_8->setHorizontalHeaderLabels(headerList_8);
	//表格内容
	for (int i = 0; i < rowsCount; ++i)
	{
		for (int j = 0; j < cloumCount; ++j)
		{
			ui.tableWidget_8->setItem(i, j, new QTableWidgetItem(QString::number(pca_result.transformed_data(i, j))));
		}
		ui.tableWidget_8->setItem(i, cloumCount, new QTableWidgetItem(QString::number(pca_result.score(i))));
	}
	//插入排序按钮
	QPushButton* btn_score = new QPushButton(QString::fromLocal8Bit("排序"));
	ui.tableWidget_8->setCellWidget(rowsCount, cloumCount, btn_score);
	connect(btn_score, SIGNAL(clicked()), this, SLOT(OnActionSort()));
	return;
}

void LargeSampleSimulationUI::OnActionSort()
{
	VectorXi ind;
	VectorXd sorted_score;
	pca->sort_vec(pca_result.score, sorted_score, ind);//综合得分排序，从大到小
	//cout << "综合得分排序：\n" << sorted_score << endl;
	//cout << "排序后各元素对应的原始得分中的位置：\n" << ind << endl;
	MatrixXd sorted_transformed_data(pca_result.transformed_data.rows(), pca_result.transformed_data.cols());
	for (int i = 0; i < pca_result.transformed_data.rows(); ++i)
	{
		for (int j = 0; j < pca_result.transformed_data.cols(); ++j)
		{
			sorted_transformed_data(i, j) = pca_result.transformed_data(ind(i), j);
			ui.tableWidget_8->setItem(i, j, new QTableWidgetItem(QString::number(sorted_transformed_data(i, j))));
		}
		ui.tableWidget_8->setItem(i, pca_result.transformed_data.cols(), new QTableWidgetItem(QString::number(sorted_score(i))));
	}

}

void LargeSampleSimulationUI::CorrelationAnalysis()
{
	ui.tableWidget_6->setAlternatingRowColors(true);//隔行变色
	ui.tableWidget_6->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);      //行高自动填充
	ui.tableWidget_6->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);  //列宽自动填充
	int rowsCount = pca_result.corCoefficient.rows();
	int cloumCount = pca_result.corCoefficient.cols();
	ui.tableWidget_6->setRowCount(rowsCount);
	ui.tableWidget_6->setColumnCount(cloumCount);
	QStringList horizontalHeaderList;
	//corCoefficient 转成二维vector
	std::vector< std::vector<double> > vCorCoefficient(rowsCount, std::vector<double>(cloumCount));
	std::vector<std::string> vNames;
	//表头
	for (int i = 0; i < cloumCount; i++) {
		QString headerStr = QString::fromLocal8Bit("结果") + QString::number(i + 1);
		horizontalHeaderList.append(headerStr);
		std::string vNames_str = headerStr.toLocal8Bit();
		vNames.push_back(vNames_str);
	}
	ui.tableWidget_6->setHorizontalHeaderLabels(horizontalHeaderList);
	ui.tableWidget_6->setVerticalHeaderLabels(horizontalHeaderList);
	for (int i = 0; i < rowsCount; i++) {
		for (int j = 0; j < cloumCount; j++) {
			vCorCoefficient[i][j] = pca_result.corCoefficient(i, j);
			ui.tableWidget_6->setItem(i, j, new QTableWidgetItem(QString::number(pca_result.corCoefficient(i, j))));
		}
	}
	ui.widget_heatMap->drawHeatMap(vCorCoefficient, vNames);
}

/* Description:	进行单因素方差分析
 * Input:		int selectedResId  要进行方差分析的结果序号
				int sampleNum	   对结果样本分组的个数
				int minSampleSize  每个样本组的最小容量
 * Output:		vector<float>& res 方差分析结果，存储当前所选结果对应的所有因素的p值
 * Return:  	计算成功返回true,计算失败返回false
 * Others:   */
bool LargeSampleSimulationUI::VarianceAnalysis(int selectedResId, int sampleNum, int minSampleSize, std::vector<float>& res)
{
	//对结果数组按指定的某个结果（序号为selectedResId）的大小排序
	std::sort(vAvrRes_anova.begin(), vAvrRes_anova.end(),
		[selectedResId](std::vector<std::pair<int, float>> a, std::vector<std::pair<int, float>> b) {return a[selectedResId].second < b[selectedResId].second; });

	std::vector<std::vector<int>> resHash(sampleNum);	//二维数组，所有结果按样本分组后，其序号存储于此
	float minRes = vAvrRes_anova[0][selectedResId].second;
	float maxRes = vAvrRes_anova[vAvrRes_anova.size() - 1][selectedResId].second;
	float step = (maxRes - minRes + 0.0001) / sampleNum;

	for (int i = 0; i < vAvrRes_anova.size(); i++) {
		float tmpRes = vAvrRes_anova[i][selectedResId].second;
		for (int sampleIdx = 0; sampleIdx < sampleNum; sampleIdx++) {
			if (tmpRes >= minRes + sampleIdx * step && tmpRes < minRes + (sampleIdx + 1)*step) {
				resHash[sampleIdx].emplace_back(i);
				break;
			}
		}
	}
	//将样本按频数排序
	std::sort(resHash.begin(), resHash.end(), [](std::vector<int>a, std::vector<int>b) {return a.size() < b.size(); });

	bool findFlag = false;
	int sampleSize = 0;
	int beginSampleIdx = sampleNum - 1;
	//对已排序的样本进行遍历，找到第一个超过样本最小容量minSampleSize的样本，记录
	for (int i = 0; i < sampleNum; i++) {
		if (resHash[i].size() >= minSampleSize) {
			findFlag = true;
			sampleSize = resHash[i].size();
			beginSampleIdx = i;
			break;
		}
	}

	//若符合要求的样本个数小于等于1，则无法进行方差分析，退出
	if (beginSampleIdx >= sampleNum - 1)
		return false;


	for (int factorIdx = 0; factorIdx < factorNames.size(); factorIdx++) {
		std::vector<std::vector<float>> data;	//方差分析的输入，每个样本中元素对应的水平

		//将符合条件（即样本大小满足要求）的样本对应的水平赋值给data
		for (int idx = beginSampleIdx; idx < sampleNum; idx++) {
			std::vector <float>tmp;
			for (int i = 0; i < sampleSize; i++) {
				int gkId = vAvrRes_anova[resHash[idx][i]][selectedResId].first; //所对应的工况id
				tmp.emplace_back(GKData[gkId][factorIdx]);
			}
			data.emplace_back(std::move(tmp));
		}
		//进行方差分析
		anov_result anovRes = anova(data);
		res.emplace_back(anovRes.f);
	}
	return true;
}

//创建文件夹 先创建data文件夹 
//每次添加任务时在data文件夹下再创建一个以当前时间命名的文件夹 
//用来存放当前任务的工况表、想定表、结果表
int LargeSampleSimulationUI::CreatCurTaskDataFolder()
{
	char folderPath[100];
	char folderFullPath[200];
	sprintf(folderPath, ".\\data");
	if (access(folderPath, 0))
	{
		if (mkdir(folderPath) == -1)
		{
			//log.ERROR_log("时域积分结果文件创建失败");
			//ErrorHandlerFunction();
			return -1;
		}
	}
	QString datatime = QDateTime::currentDateTime().toString("yyyy.MM.dd.hh_mm_ss");
	sprintf(folderPath, ".\\data\\%s", datatime.toStdString().c_str());
	if (access(folderPath, 0))
	{
		if (mkdir(folderPath) == -1)
		{
			//log.ERROR_log("时域积分结果文件创建失败");
			//ErrorHandlerFunction();
			return -1;
		}
	}
	curFolderPath = folderPath;
	taskStatus = QString::fromLocal8Bit("任务文件夹已创建");
}

void LargeSampleSimulationUI::OnActionCreateGongKuang()
{
	ui.tabWidget->setCurrentIndex(1);
	if (taskStatus == QString::fromLocal8Bit("因素水平表已读")) {
		CreatCurTaskDataFolder();
	}
	//生成工况表部分 生成的工况表以txt形式存储
	char buffer[200];
	getcwd(buffer, 200);
	std::string curpath(buffer);//得到当前运行目录
	std::string path_GK = curpath + curFolderPath.toStdString().erase(0, 1) + "\\gk.txt";//得到工况表全路径（删掉了curFolderPath最前面的.）
	m_path_GK = QString::fromLocal8Bit(path_GK.c_str());

	std::ofstream ofs;
	std::string factorLevelPath = curpath + curFolderPath.toStdString().erase(0, 1) + "\\factor_level_table.txt";
	ofs.open(factorLevelPath.c_str(), std::ios::out);

	for (int j = 0; j < factorNames.size(); j++)
	{
		std::string tmp = factorNames[j].toStdString() + ":";
		for (int i = 0; i < FactorLevelData.size(); i++)
		{
			tmp += std::to_string(FactorLevelData[i][j]) + " ";
		}
		ofs << tmp << "\n";
	}
	ofs.close();
	nCol = factorNames.size();
	//调用python,进行正交实验表生成
	std::string curpath_fol = curpath + curFolderPath.toStdString().erase(0, 1);
	m_TaskDataFolderPath = QString::fromStdString(curpath_fol);
	if (ui.comboBox->currentIndex() == 0)//判断选择的是正交试验设计则调用Python进行正交试验设计
	{
		std::string command = "python " + curpath + "\\test2.py " + curpath_fol + "\\factor_level_table.txt " + path_GK + " oat";//正交"oat"
		system(command.c_str());
	}
	else if (ui.comboBox->currentIndex() == 1)//判断选择的是全因子试验设计则调用Python进行全因子试验设计
	{
		std::string command = "python " + curpath + "\\test2.py " + curpath_fol + "\\factor_level_table.txt " + path_GK + " full";//全因子"full"
		system(command.c_str());
	}

	taskStatus = QString::fromLocal8Bit("工况表已生成");

	//添加到数据库
	curTaskId = sql->getTaskListLastId() + 1;
	//QString str_id = QString::number(id);
	QString str_factorName = factorNames.join(" ");
	QString str_curpath_fol = QString::fromLocal8Bit(curpath_fol.c_str());
	//emit (updateTaskInfo(id, str_factorName, str_curpath_fol, QString::fromLocal8Bit("工况表已生成")));
	emit(updateTaskInfo(curTaskId, str_factorName, str_curpath_fol, taskStatus));


	//显示工况表
	OndisplayTxt_GK(m_path_GK);

}

void LargeSampleSimulationUI::OnActionCreateXiangding()   //生成并显示想定表
{
	ui.tabWidget->setCurrentIndex(2);

	/*生成想定部分 生成的想定以txt形式存储    更新想定表路径


	*/
	taskStatus = QString::fromLocal8Bit("想定表已生成");
	emit(changeTaskStatus(curTaskId, taskStatus));
	m_path_XD = "D://data//XD0.txt";      //测试用
	OndisplayTxt_XD(m_path_XD);
	ui.comboBox_2->setEnabled(true);

}

//显示因素水平表(读txt)
void LargeSampleSimulationUI::OndisplayTxt_FL(const QString &FilePath_FL)
{
	ui.lineEdit->setText(FilePath_FL);
	ui.tableWidget->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);//固定行高
	ui.tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//列宽自动填充

	QFile t_file(FilePath_FL);
	if (!t_file.open(QIODevice::ReadOnly))
	{
		QMessageBox::information(this, tr("information"), tr("File opening failed"));
		return;
	}
	QTextStream t_in(&t_file);
	QVector<QStringList> t_data;  //文件内容

	//读因素水平表txt
	while (!t_in.atEnd())
	{
		//分割":"与" "
		QString t_line = t_in.readLine();
		QString vars = t_line.split(':').last();
		QStringList var_list = vars.simplified().split(' ');	//去除vars中前后空格，再按空格分割
		t_data.append(var_list);
	}
	//设置表头为因素名
	ui.tableWidget->setRowCount(t_data[0].count());
	ui.tableWidget->setColumnCount(nCol);
	ui.tableWidget->setHorizontalHeaderLabels(factorNames);

	//表格内容
	for (int i = 0; i < t_data.size(); i++)
	{
		for (int j = 0; j < t_data[i].count(); j++)
		{
			ui.tableWidget->setItem(j, i, new QTableWidgetItem(t_data[i][j]));
		}
	}
}

//显示工况表(读txt)
void LargeSampleSimulationUI::OndisplayTxt_GK(const QString &FilePath_GK)
{
	m_path_GK = FilePath_GK;
	ui.lineEdit_2->setText(m_path_GK);
	ui.tableWidget_2->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);//固定行高
	ui.tableWidget_2->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//列宽自动填充
	ui.tableWidget_2->setAlternatingRowColors(true);//隔行变色

	QFile t_file(m_path_GK);
	if (!t_file.open(QIODevice::ReadOnly))
	{
		QMessageBox::information(this, tr("information"), tr("File opening failed"));
		return;
	}
	QTextStream t_in(&t_file);
	QVector<QStringList> t_data;  //文件内容

	//读第一行，更新因素列表
	QString t_line = t_in.readLine().simplified();
	QStringList t_list = t_line.split(' ');
	this->factorNames = t_list;
	this->nCol = t_list.size();

	int t_rowCount = 0;     //文件读取行数，同于设置表格行数
	while (!t_in.atEnd())
	{
		t_line = t_in.readLine();
		t_list = t_line.split(' ');
		t_data.append(t_list);
		t_rowCount++;
	}
	this->nCol = factorNames.size();
	this->curXDNums = t_rowCount;
	//设置表头为因素名
	ui.tableWidget_2->setRowCount(t_rowCount);
	ui.tableWidget_2->setColumnCount(nCol);
	ui.tableWidget_2->setHorizontalHeaderLabels(factorNames);

	//表格内容
	for (int i = 0; i < t_data.size(); i++)
	{
		std::vector<float> tmp(t_data[i].count());
		for (int j = 0; j < t_data[i].count(); j++)
		{
			tmp[j] = t_data[i][j].toFloat();
			ui.tableWidget_2->setItem(i, j, new QTableWidgetItem(t_data[i][j]));
		}
		if (!isGKDataLoad)
			GKData.emplace_back(std::move(tmp));
	}
	isGKDataLoad = true;

	//查询当前有没有结果，有结果则显示结果
	QString resultFileName = m_TaskDataFolderPath + "\\avr_res.txt";
	QFile res_file(resultFileName);

	//没有这个文件，说明没有结果，退出
	if (!res_file.open(QIODevice::ReadOnly))
	{
		return;
	}
	QTextStream res_in(&res_file);
	t_line.clear();
	t_list.clear();
	QVector<QStringList> res_data;  //结果文件内容
	while (!res_in.atEnd())
	{
		t_line = res_in.readLine().simplified();
		t_list = t_line.split(' ');
		res_data.append(t_list);
	}
	//若结果为空，退出
	if (res_data.empty())
		return;

	//插入新列
	int newInsertColNums = res_data[0].length();
	int oldColNum = ui.tableWidget_2->columnCount();
	for (int i = 0; i < newInsertColNums; i++)
	{
		ui.tableWidget_2->insertColumn(oldColNum + i);
	}
	//设置新表头
	QStringList resHead = { QString::fromLocal8Bit("结果1"),QString::fromLocal8Bit("结果2"), QString::fromLocal8Bit("结果3"), QString::fromLocal8Bit("结果4"),
		QString::fromLocal8Bit("结果5"), QString::fromLocal8Bit("结果6"), QString::fromLocal8Bit("结果7"), QString::fromLocal8Bit("结果8") };
	QStringList newHeadLabel = factorNames + resHead;
	ui.tableWidget_2->setHorizontalHeaderLabels(newHeadLabel);
	//显示结果
	for (int i = 0; i < res_data.size(); i++)
	{
		for (int j = 0; j < newInsertColNums; j++)
			ui.tableWidget_2->setItem(i, oldColNum + j, new QTableWidgetItem(res_data[i][j]));
	}
}

//显示想定表(读txt)
void LargeSampleSimulationUI::OndisplayTxt_XD(const QString &FilePath_XD)
{
	if (taskStatus == QString::fromLocal8Bit("计算完成")) {
		ui.comboBox_2->setEnabled(true);//效能评估功能开放
	}

	//m_path_XD = QFileDialog::getOpenFileName(this, tr("Open file"), "C:\\");
	m_path_XD = FilePath_XD;
	ui.lineEdit_3->setText(m_path_XD);
	ui.tableWidget_3->setAlternatingRowColors(true);//隔行变色
	ui.tableWidget_3->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);//固定行高
	ui.tableWidget_3->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//列宽自动填充

	QFile t_file(m_path_XD);
	if (!t_file.open(QIODevice::ReadOnly))
	{
		QMessageBox::information(this, tr("information"), tr("File opening failed"));
		return;
	}
	QTextStream t_in(&t_file);
	int t_rowCount = 0;     //文件读取行数，同于设置表格行数
	QVector<QStringList> t_data;  //文件内容
	while (!t_in.atEnd())
	{
		QString t_line = t_in.readLine();
		QStringList t_list = t_line.split(' ');
		QString str = t_list[0];
		t_data.append(t_list);
		t_rowCount++;
	}
	this->curSendWindowLen = t_rowCount;//发送窗口长度，当前设置等于想定表行数
	QStringList t_headerList;
	int t_cloumCount = t_data[0].size();//设置表格列数

	ui.tableWidget_3->setRowCount(t_rowCount);
	ui.tableWidget_3->setColumnCount(t_cloumCount);

	//表头
	for (int i = 0; i < t_cloumCount; i++)
	{
		QString t_headerStr = "column" + QString::number(i + 1);
		t_headerList.append(t_headerStr);
	}
	ui.tableWidget_3->setHorizontalHeaderLabels(t_headerList);
	//表格内容
	for (int i = 0; i < t_data.size(); i++)
	{
		for (int j = 0; j < t_data[i].count(); j++)
		{
			ui.tableWidget_3->setItem(i, j, new QTableWidgetItem(t_data[i][j]));
		}
	}

	//最后一列插入数据回放按钮
	//如果此时显示的想定表还没有收到数据，则不加回放按钮
	QString resultFileName = m_TaskDataFolderPath + "\\res_plot_" + QString::number(curDisplayId) + ".txt";//注意！还没有为curDisplayId添加更新逻辑，此处默认是0
	QFile res_file(resultFileName);
	//没有这个文件，说明没有结果，退出
	if (!res_file.open(QIODevice::ReadOnly))
		return;
	QTextStream res_in(&res_file);
	QString t_line;
	QStringList t_list;
	QVector<QStringList> res_data;  //结果文件内容
	while (!res_in.atEnd())
	{
		t_line = res_in.readLine().simplified();
		t_list = t_line.split(' ');
		res_data.append(t_list);
	}
	//若结果为空，退出
	if (res_data.empty())
		return;

	//插入新列
	int newInsertColNums = res_data[0].length() + 1;
	int oldColNum = ui.tableWidget_3->columnCount();
	for (int i = 0; i < newInsertColNums; i++)
	{
		ui.tableWidget_3->insertColumn(oldColNum + i);
	}
	//设置新表头
	QStringList resHead = { QString::fromLocal8Bit("数据回放"),QString::fromLocal8Bit("结果1"),QString::fromLocal8Bit("结果2"), QString::fromLocal8Bit("结果3"), QString::fromLocal8Bit("结果4"),
		QString::fromLocal8Bit("结果5"), QString::fromLocal8Bit("结果6"), QString::fromLocal8Bit("结果7"), QString::fromLocal8Bit("结果8") };
	QStringList newHeadLabel = t_headerList + resHead;
	ui.tableWidget_3->setHorizontalHeaderLabels(newHeadLabel);
	//显示结果,并添加按钮
	for (int i = 0; i < res_data.size(); i++)
	{
		QPushButton *btn = new QPushButton(QString::fromLocal8Bit("数据回放"));
		//为按钮设置属性"row"，之后槽函数中可以根据调用对象的row来判断点击了第几行的按钮
		btn->setProperty("row", i);
		connect(btn, SIGNAL(clicked()), this, SLOT(OnActionPlotShow()));
		ui.tableWidget_3->setCellWidget(i, oldColNum, btn);
		for (int j = 0; j < res_data[0].length(); j++)
		{
			ui.tableWidget_3->setItem(i, oldColNum + 1 + j, new QTableWidgetItem(res_data[i][j]));
		}

	}
}

void LargeSampleSimulationUI::OndisplayAll(const QString &TaskDataFolderPath, const QString& TaskStatu)
{
	ui.stackedWidget->setCurrentIndex(1);
	ui.tabWidget->setCurrentIndex(0);
	//显示因素水平表
	m_path_FL = TaskDataFolderPath + "\\factor_level_table.txt";
	m_TaskDataFolderPath = TaskDataFolderPath;
	ui.lineEdit->setText(m_path_FL);

	//工况表、想定表路径，默认显示第一个想定表
	QString FilePath_GK = TaskDataFolderPath + "\\gk.txt";
	QString FilePath_XD = TaskDataFolderPath + "\\xd_0.txt";

	if (TaskStatu == QString::fromLocal8Bit("工况表已生成"))
	{
		OndisplayTxt_GK(FilePath_GK);//因在显示工况表时更新当前任务的因素列表，故先调用
		OndisplayTxt_FL(m_path_FL);
		//ui.pushButton_3->setEnabled(false);  //导入因素水平表按钮不可用
		ui.pushButton->setEnabled(false);  //生成工况按钮不可用
		return;
	}
	else if (TaskStatu == QString::fromLocal8Bit("想定表已生成"))
	{
		OndisplayTxt_GK(FilePath_GK);
		OndisplayTxt_FL(m_path_FL);
		FilePath_XD = "D://data//XD0.txt";      //测试用
		OndisplayTxt_XD(FilePath_XD);
		//ui.pushButton_3->setEnabled(false);  //导入因素水平表按钮不可用
		ui.pushButton->setEnabled(false);  //生成工况按钮不可用
		ui.pushButton_2->setEnabled(false);  //生成想定按钮不可用
		ui.comboBox_2->setEnabled(true);  //效能评估可用
		return;
	}
	else if (TaskStatu == QString::fromLocal8Bit("开始计算"))
	{
		OndisplayTxt_GK(FilePath_GK);
		OndisplayTxt_FL(m_path_FL);
		FilePath_XD = "D://data//XD0.txt";      //测试用
		OndisplayTxt_XD(FilePath_XD);
		//ui.pushButton_3->setEnabled(false);  //导入因素水平表按钮不可用
		ui.pushButton->setEnabled(false);  //生成工况按钮不可用
		ui.pushButton_2->setEnabled(false);  //生成想定按钮不可用
		ui.pushButton_4->setEnabled(false);  //确认执行按钮不可用
		ui.comboBox_2->setEnabled(false);  //效能评估不可用
		return;
	}
	else   //计算完成
	{
		OndisplayTxt_GK(FilePath_GK);
		OndisplayTxt_FL(m_path_FL);
		FilePath_XD = "D://data//XD0.txt";      //测试用
		OndisplayTxt_XD(FilePath_XD);
		OndisplayTxt_avr_res();
		//ui.pushButton_3->setEnabled(false);  //导入因素水平表按钮不可用
		ui.pushButton->setEnabled(false);  //生成工况按钮不可用
		ui.pushButton_2->setEnabled(false);  //生成想定按钮不可用
		ui.pushButton_4->setEnabled(false);  //确认执行按钮不可用
		return;
	}
}

//显示结果表
void LargeSampleSimulationUI::OndisplayTxt_avr_res()
{
	ui.tableWidget_4->setAlternatingRowColors(true);//隔行变色
	ui.tableWidget_4->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);//固定行高
	ui.tableWidget_4->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//列宽自动填充
	ui.tableWidget_7->setAlternatingRowColors(true);//隔行变色
	ui.tableWidget_7->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);//固定行高
	ui.tableWidget_7->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//列宽自动填充
	ui.tableWidget_10->setAlternatingRowColors(true);//隔行变色
	ui.tableWidget_10->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);//固定行高
	ui.tableWidget_10->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//列宽自动填充

	//方差分析页面初始化
	modelAnova = new QStandardItemModel();
	modelAnova->setColumnCount(factorNames.size() + 1);
	QStringList header = factorNames;
	header.push_front(QString::fromLocal8Bit("已选结果"));
	modelAnova->setHorizontalHeaderLabels(header);
	ui.tableView_5->setModel(modelAnova);   //将数据模型与TableView绑定
	ui.tableView_5->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
	ui.tableView_5->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
	ui.tableView_5->setAlternatingRowColors(true);//隔行变色  
	ui.tableView_5->setSelectionBehavior(QAbstractItemView::SelectRows);//设置选中时为整行选中   
	ui.tableView_5->verticalHeader()->setHidden(false);//设置显示每行序号


	QString resultFileName = m_TaskDataFolderPath + "\\avr_res.txt";
	QFile res_file(resultFileName);
	//没有这个文件，说明没有结果，退出
	if (!res_file.open(QIODevice::ReadOnly))
		return;
	QTextStream res_in(&res_file);
	QString t_line;
	QStringList t_list;
	QVector<QStringList> res_data;  //结果文件内容
	while (!res_in.atEnd())
	{
		t_line = res_in.readLine().simplified();
		t_list = t_line.split(' ');
		res_data.append(t_list);
	}

	ui.tableWidget_4->setRowCount(res_data.size());
	ui.tableWidget_4->setColumnCount(res_data[0].length());
	ui.tableWidget_7->setRowCount(res_data.size());
	ui.tableWidget_7->setColumnCount(res_data[0].length());
	ui.tableWidget_10->setRowCount(res_data.size());
	ui.tableWidget_10->setColumnCount(res_data[0].length());
	//设置表头为因素名
	QStringList resHead = { QString::fromLocal8Bit("结果1"),QString::fromLocal8Bit("结果2"), QString::fromLocal8Bit("结果3"), QString::fromLocal8Bit("结果4"),
		QString::fromLocal8Bit("结果5"), QString::fromLocal8Bit("结果6"), QString::fromLocal8Bit("结果7"), QString::fromLocal8Bit("结果8") };
	ui.tableWidget_4->setHorizontalHeaderLabels(resHead);
	ui.tableWidget_7->setHorizontalHeaderLabels(resHead); 
	ui.tableWidget_10->setHorizontalHeaderLabels(resHead);

	//表格内容
	for (int i = 0; i < res_data.size(); i++)
	{
		std::vector<std::pair<int, float>> rowAvrRes_anova;
		std::vector<double>rowAvrRes_pca;
		for (int j = 0; j < res_data[i].count(); j++)
		{
			ui.tableWidget_4->setItem(i, j, new QTableWidgetItem(res_data[i][j]));
			ui.tableWidget_7->setItem(i, j, new QTableWidgetItem(res_data[i][j]));
			ui.tableWidget_10->setItem(i, j, new QTableWidgetItem(res_data[i][j]));
			float temp = res_data[i][j].toFloat();
			rowAvrRes_anova.push_back({ i,temp });
			double temp1 = res_data[i][j].toDouble();
			rowAvrRes_pca.push_back(temp1);

		}
		vAvrRes_anova.push_back(rowAvrRes_anova);
		vAvrRes_pca.push_back(rowAvrRes_pca);
	}
}

//获取数据库内容的行数
int LargeSampleSimulationUI::getModelRowCount()
{
	//不加这个获取的最大行数为256
	while (model->canFetchMore())
	{
		model->fetchMore();
	}
	return model->rowCount();
}

void LargeSampleSimulationUI::OnStartRun(const QString taskFilePath, int XDNums, int sendWindowLen)
{
	this->calcuTaskPath.append(taskFilePath);
	this->curXDNums = XDNums;
	this->sendWindowLen = sendWindowLen;
	this->calcuthread->setSendWindowLen(sendWindowLen);
	sendCalcuCommand();
}

//发送任务
void LargeSampleSimulationUI::sendCalcuCommand()
{
	sendData.clear();
	int sendId = curRecvId + 1;
	//打开当前工况生成的想定表所在文件夹 读取一个想定表
	//将其中的数据存入内存
	QString XDPath = calcuTaskPath.first() + "\\xd_" + QString::number(sendId) + ".txt";
	std::string str = XDPath.toStdString();
	const char* XDPath_ch = str.c_str();
	InputStruct1* myXDStr = new InputStruct1[sendWindowLen];
	int i = 0;
	ifstream infile(XDPath_ch, ios::in);
	if (!infile)
	{
		QMessageBox::warning(this, QString::fromLocal8Bit("错误提示"), QString::fromLocal8Bit("无法打开想定文件"));
		return;
	}
	while (!infile.eof())
	{
		infile >> myXDStr[i].param1 >> myXDStr[i].param2 >> myXDStr[i].param3 >> myXDStr[i].param4 >> myXDStr[i].param5 >> myXDStr[i].param6;
		myXDStr[i].idx = i;
		sendData.push_back(myXDStr[i]);
		i++;
	}
	infile.close();

	//向服务器发数据
	InputStruct1* p_XD = sendData.data();
	int myXDLength = sendData.size();
	//设置发送的命令帧 CONFIG_DATA
	Frame frame;
	frame.command = CommCommand::CONFIG_DATA;
	frame.length = myXDLength;
	int l = 0;
	//发送命令帧
	l = socket->write((char*)&frame, sizeof(frame));
	socket->waitForBytesWritten(3000);
	socket->flush();
	//发送数据
	l = socket->write((char*)p_XD, myXDLength * sizeof(InputStruct1));
	socket->waitForBytesWritten(3000);
	socket->flush();

	//发送计算帧
	frame.command = CommCommand::CALCU;
	l = socket->write((char*)&frame, sizeof(frame));
	socket->waitForBytesWritten(3000);
	socket->flush();
	status = RUNNING;
}

//计算结果写入txt 
void LargeSampleSimulationUI::OnActionSaveRes(ResStruct* Resptr, int resNum)
{
	++curRecvId;
	//将数据存储到文件
	QString fileName = calcuTaskPath.first() + "\\res_" + QString::number(curRecvId) + ".txt";
	std::string str = std::string((const char *)fileName.toLocal8Bit().constData());
	ofstream outfile(str, ios::out);
	if (!outfile.is_open())
	{
		qDebug() << "creat res file wrong!";
		return;
	}

	//存各结果的和，以计算均值
	int sum_int_res[3] = { 0,0,0 };
	float sum_float_res[3] = { 0,0,0 };
	for (int i = 0; i < resNum; i++)
	{
		sum_int_res[0] += Resptr[i].Res1;
		sum_int_res[1] += Resptr[i].Res2;
		sum_int_res[2] += Resptr[i].Res3;
		sum_float_res[0] += Resptr[i].Res4;
		sum_float_res[1] += Resptr[i].Res5;
		sum_float_res[2] += Resptr[i].Res6;
		outfile << Resptr[i].Res1 << ' ';
		outfile << Resptr[i].Res2 << ' ';
		outfile << Resptr[i].Res3 << ' ';
		outfile << Resptr[i].Res4 << ' ';
		outfile << Resptr[i].Res5 << ' ';
		outfile << Resptr[i].Res6 << endl;
	}
	outfile.close();
	//均值追加写入文件avr_res_X.txt,供工况表显示
	sum_int_res[0] /= resNum;
	sum_int_res[1] /= resNum;
	sum_int_res[2] /= resNum;
	sum_float_res[0] /= resNum;
	sum_float_res[1] /= resNum;
	sum_float_res[2] /= resNum;
	fileName = calcuTaskPath.first() + "\\avr_res.txt";
	outfile.open(fileName.toLocal8Bit().data(), ios::out | ios::app);
	outfile << sum_int_res[0] << ' ' << sum_int_res[1] << ' ' << sum_int_res[2] << ' '
		<< sum_float_res[0] << ' ' << sum_float_res[1] << ' ' << sum_float_res[2] << endl;
	outfile.close();


	//若想定表没有发送完，则继续发送下一个
	if (curRecvId < curXDNums - 1)
	{
		sendCalcuCommand();
	}
	//否则，当前任务说明计算完成
	else
	{
		//计算完成
		calcuTaskPath.pop_front();
		curRecvId = -1;
		curXDNums = 0;
		status = FINISH;
		settaskStatusFinish();
	}
}

//连接网络按钮槽函数
void LargeSampleSimulationUI::OnActionConnect()
{   
	if (curRepeatNum == 0)
	{
		ConnectDialog *connectdialog = new ConnectDialog(&ip, &port);
		connectdialog->show();
		while (true)
		{
			if (QDialog::Accepted == connectdialog->exec())
			{
				socket = new QTcpSocket();
				
				socket->connectToHost(ip, port);
				if (!socket->waitForConnected(3000))
				{
					QMessageBox::critical(this, QString::fromLocal8Bit("错误"), QString::fromLocal8Bit("连接失败"), QMessageBox::Ok);
					emit printInfo(QString::fromLocal8Bit("连接失败！"));
					continue;
				}
				emit printInfo(QString::fromLocal8Bit("连接成功！"));

				connect(socket, SIGNAL(readyRead()), this, SLOT(OnSocketReadyRead()));
				connect(socket, SIGNAL(disconnected()), this, SLOT(OnDisconnect()), Qt::QueuedConnection);
				status = WAITFORCONFIG;
				break;
			}
			break;
		}
		delete connectdialog;
	}
	//网络断开后重连
	else if (curRepeatNum > 0)
	{
		socket = new QTcpSocket();
		socket->connectToHost(ip, port);
		if (!socket->waitForConnected(3000))
		{
			emit printInfo(QString::fromLocal8Bit("网络重连失败"));
			ErrorHandleFunction();
			return;
		}
		emit printInfo(QString::fromLocal8Bit("重连成功！"));
		connect(socket, SIGNAL(readyRead()), this, SLOT(OnSocketReadyRead()));
		connect(socket, SIGNAL(disconnected()), this, SLOT(OnDisconnect()), Qt::QueuedConnection);
		curRepeatNum = 0;
		Sleep(3000);
		status = WAITFORCONFIG;
		sendCalcuCommand();
	}
	
}

//网络断开时触发
void LargeSampleSimulationUI::OnDisconnect()
{
	delete socket;
	calcuthread->ClearFrameQueue();
	
	//非运行状态下断开网络，弹窗选择是否重连
	if (status != RUNNING) {
		status = WAITFORCONNECT;
		if (QMessageBox::No == QMessageBox::question(this, "warning", QString::fromLocal8Bit("网络已断开，是否尝试重连"), QMessageBox::Yes, QMessageBox::No))
			return;
	}

	//运行状态下网络断开，自动重连
	status = WAITFORCONNECT;
	ErrorHandleFunction();
}

void LargeSampleSimulationUI::OnPopMenue(QPoint pos) {
	auto index = ui.tableView->indexAt(pos);
	if (index.isValid())
	{
		//根据点击的不同选项，运行popMenu右键菜单中不同的槽函数
		popMenu->exec(QCursor::pos()); // 菜单出现的位置为当前鼠标的位置
	}
}

void LargeSampleSimulationUI::OnDeletTask() {
	QItemSelectionModel *smodel = ui.tableView->selectionModel();//取出选中的模型
	QModelIndexList list = smodel->selectedRows();//取出模型的索引
	if (QMessageBox::No == QMessageBox::question(this, "warning", QString::fromLocal8Bit("是否删除选中的%1条任务？与之相关的数据也会被删除").arg(list.size()), QMessageBox::Yes, QMessageBox::No))
		return;
	//删除所有选中的行
	for (int i = 0; i < list.size(); i++)
	{
		model->removeRow(list.at(i).row());
	}
	model->submitAll();                //更改之后调用submitAll(); 将所做的更改更新到数据库中
}

//读取配置文件界面
void LargeSampleSimulationUI::OnActionExcel()
{
	connect(this, SIGNAL(updateTaskInfo(const int, const QString&, const QString&, const QString&)),
		this, SLOT(OnUpdateTaskInfo(const int, const QString&, const QString&, const QString&)));
	//connect(tablewidget, SIGNAL(updateTaskInfo(const int, const QString&, const QString&)),
	//	this, SLOT(OnUpdateTaskInfo(const int, const QString&, const QString&)));
	connect(this, SIGNAL(changeTaskStatus(const int, const QString&)),
		this, SLOT(OnChangeTaskStatus(const int, const QString&)));
	connect(this, SIGNAL(StartRun(const QString, int, int)), this, SLOT(OnStartRun(const QString, int, int)));
	//connect(tablewidget, SIGNAL(CloseFactorTbaleWidget()), this, SLOT(OnCloseFactorTbaleWidget()));

	setUsersqlptr(sql);
	//tablewidget->show();
}


//接收socket数据槽函数
void LargeSampleSimulationUI::OnSocketReadyRead()
{
	while (true)
	{
		if (socket->bytesAvailable() != 0)
		{
			int length = socket->read(((char*)&recvFrame + recvLength), sizeof(Frame) - recvLength);
			recvLength += length;
			if (recvLength == sizeof(Frame))
			{
				calcuthread->PushFrame(recvFrame);
				recvLength = 0;
				continue;
			}
		}
		else
		{
			break;
		}
	}
}

void LargeSampleSimulationUI::OnUpdateTaskInfo(const int id, const QString& FactorName, const QString &FilePath, const QString &status) {
	QString str_id = QString::number(id);
	this->sql->addTaskInfo(str_id, FactorName, FilePath, status);
	model->submitAll();

	//更新任务列表之后 重新插入查看按钮
	model->insertColumn(5);//在模型的第4列后面插入一列，放按钮
	model->setHeaderData(5, Qt::Horizontal, QString::fromLocal8Bit("   任务详情   "));
	//将数据模型与TableView绑定
	ui.tableView->setModel(model);
	//最后一列插入打开按钮
	for (int i = 0; i < getModelRowCount(); i++)
	{
		QPushButton *btn = new QPushButton(QString::fromLocal8Bit("查看"));
		btn->setProperty("row", i);
		connect(btn, SIGNAL(clicked()), this, SLOT(OnPushbuttonCheck()));
		ui.tableView->setIndexWidget(model->index(i, 5), btn);
	}
}

void LargeSampleSimulationUI::OnChangeTaskStatus(const int id, const QString &Status)
{
	QString str_id = QString::number(id);
	this->sql->updateTaskStatus(str_id, Status);
	model->submitAll();

	//更新任务列表之后 重新插入查看按钮
	model->insertColumn(5);//在模型的第4列后面插入一列，放按钮
	model->setHeaderData(5, Qt::Horizontal, QString::fromLocal8Bit("   任务详情   "));
	//将数据模型与TableView绑定
	ui.tableView->setModel(model);
	//最后一列插入打开按钮
	for (int i = 0; i < getModelRowCount(); i++)
	{
		QPushButton *btn = new QPushButton(QString::fromLocal8Bit("查看"));
		btn->setProperty("row", i);
		connect(btn, SIGNAL(clicked()), this, SLOT(OnPushbuttonCheck()));
		ui.tableView->setIndexWidget(model->index(i, 5), btn);
	}
}


void LargeSampleSimulationUI::ReloadSql()
{
	//QSqlDatabase db = QSqlDatabase::database(); // 获取默认数据库连接
	//if (db.isOpen()) {
	//	// 数据库连接是打开的
	//	qDebug() << "数据库连接已打开1";
	//}
	//else {
	//	// 数据库连接是关闭的
	//	qDebug() << "数据库连接已关闭2";
	//}
	//重连数据库
	sql = new Usersql();
	sql->DatabaseConnect();
	query = (QSqlQuery)sql->getDB();
}

//查看任务详情 通过点击最后一列按钮查看
void LargeSampleSimulationUI::OnPushbuttonCheck()
{



	ui.lineEdit->clear();
	ui.lineEdit_2->clear();
	ui.lineEdit_3->clear();
	ui.tableWidget->clear();
	ui.tableWidget_2->clear();
	ui.tableWidget_3->clear();
	ui.tableWidget_4->clear();
	ui.tableWidget_6->clear();
	ui.tableWidget_7->clear();
	ui.tableWidget_8->clear();
	ui.tableWidget_10->clear();
	ui.comboBox_2->setEnabled(false);

	//重置分析状态
	analyStatus[0] = false;
	analyStatus[1] = false;
	analyStatus[2] = false;

	QPushButton *btn = (QPushButton *)sender();
	int i = btn->property("row").toInt();

	QAbstractItemModel *Imodel = ui.tableView->model();
	QModelIndex Iindex = Imodel->index(i, 1);//index.row()为算选择的行号。1为所选中行的第一列。。
	QString dsn = QString("select * from taskList limit %1,1").arg(i);
	query.prepare(dsn);
	//query.bindValue(":id", Iindex);
	if (!query.exec())
	{
		qDebug() << query.lastError().text();
	}

	if (query.next()) 
	{
		QString filePath_FL = query.value("FactorName").toString() + "\\factor_level_table.txt";
		QString TaskDataFolderPath = query.value("TaskDataFolderPath").toString();
		QString TaskStatu = query.value("Status").toString();
		this->TaskDataFolderPath = TaskDataFolderPath.replace("/", "\\");
		OndisplayAll(this->TaskDataFolderPath, TaskStatu);
	}
	//OnActionExcel();
	setUsersqlptr(sql);
}

void LargeSampleSimulationUI::OnCloseFactorTbaleWidget()
{
	//tablewidget = nullptr;
}

//错误处理
void LargeSampleSimulationUI::ErrorHandleFunction()
{
	if(curRepeatNum==3)
		QMessageBox::warning(this, QString::fromLocal8Bit("错误提示"), QString::fromLocal8Bit("已出错重连三次，请检查系统状态"));
	++curRepeatNum;
	if (status == WAITFORCONNECT)
		OnActionConnect();
}